import org.lxw.stock._

class Diluted(val date:Long,val sg:Double/*送股*/,val px:Double/*派息*/,
             val pgj:Double/*配股价*/,val pgs:Double/*配股数*/){
  def apply(v:Long)=(v+(pgj*pgs-px)*1000)/(1+pgs+sg)+0.5 toLong
  override def toString = date+","+List(sg,pgs,pgj,px).mkString(",")
}

object Diluted{
  def getDiluted(stock:Stock,vs:List[Diluted])={
    val d=(stock.date+"").substring(0,8).toLong
    val t=vs.filter(_.date>d)
    if(t.size>0){
      var open1=stock.open
      var high1=stock.high
      var low1=stock.low
      var close1=stock.close
      var price1=stock.price
      t.foreach{v=>
        open1=v(open1)
        high1=v(high1)
        low1=v(low1)
        close1=v(close1)
        price1=v(price1)
      }
      Stock(stock.date,open1,high1,low1,close1,stock.volume,stock.amount,price1)
    } else stock
  }
  
  lazy val pwrmap={
    io.Source.fromFile("pwr.txt").getLines.toList.filter(_.startsWith("s")).
    groupBy(_.substring(0,8)).map{a1=>(a1._1,
      a1._2.map{
        a=>val t=a.split(",")
        new Diluted(t(1).toLong,t(2).toDouble,t(5).toDouble,t(4).toDouble,t(3).toDouble)
      })
    }
  }

  def apply(str:String)=if(pwrmap.contains(str))pwrmap(str) else Nil

  def flat(id:String,list:Seq[Stock],date1:Long=0l)={//前复权
    val diluteds=apply(id)
    if(list.size<=0) list else {
      val headdate=(list.head.date+"").substring(0,8).toLong
      val lastdate=if(date1==0)(list.last.date+"").substring(0,8).toLong else date1
      val tt=diluteds.filter(a=>a.date>headdate&&a.date<lastdate)
      if(tt.size>0) list.map(a=>getDiluted(a,tt)) else list;
    }
  }
}
class StockDB(val basedir:String){
  val daydir=basedir+"/day/"
  val min5dir=basedir+"/min5/"
  lazy val idmap=new java.io.File(daydir).list.filter(a=>a.size==18&&a.startsWith("day")&&a.endsWith(".txt.xz")).
    foldLeft(new scala.collection.mutable.ArrayBuffer[String]){(a,b)=> a ++= Util.fromXZFile(daydir+"/"+b)}.
    groupBy(_.substring(0,8)).map(a=>(a._1,a._2.toList.map(aa=>aa.substring(9,9+8)+aa.substring(23))))
  lazy val allstocks=(new java.io.File(daydir).list.filter(a=> !a.startsWith("day")).map(_.substring(0,8))++idmap.keys).distinct.sorted
  def day(name: String)={
    val filename=daydir+name+".txt.xz"
    val file=new java.io.File(filename)
    if(idmap.contains(name)&&file.exists)
      Util.fromXZFile(filename).filter(_<idmap(name).head.substring(0,8))++idmap(name) else if(idmap.contains(name))
      idmap(name) else if(file.exists)
      Util.fromXZFile(filename) else Nil
  }
  def xzmin5(name: String)={
  	val file=new java.io.File(min5dir+name+".txt.xz")
  	val file1=new java.io.File(min5dir+name+".txt")
  	if(file.exists) Util.fromXZFile(file) else if(file1.exists) io.Source.fromFile(file1).getLines.toList else Nil
  }
  def min5(name: String)={
  	val l=xzmin5(name)
  	if(l.size==0) get(name) else get(name).filter(_<l.head.substring(0,12)) ++ l
 	}
  def min5list(name: String,flatdate:Long=0l,size:Int=Int.MaxValue)=
  	Min5Array(Diluted.flat(name,min5(name).takeRight(size/48*48).map(Stock(_)),flatdate).toArray)
  import collection.JavaConversions._
  private val namelist=new java.io.File(basedir).listFiles.
        filter{str=>val a=str.toString.substring(basedir.size+1);
          a.endsWith(".zip")&&a.startsWith("min5")}.sortBy(_.toString).
        foldLeft(List.empty[String]){(a,zipname)=>
    val zip=new java.util.zip.ZipFile(zipname)
    val ret11=a++(zip.entries.map(_.toString).filter(a=>a.size>10 && a.endsWith(".txt")).
      toList.map(zipname+";"+_)).sortBy(_.toString)
    zip.close
    ret11
  }
  private def get(name: String)= {
    val t1=namelist.filter(_.endsWith(name+".txt")).foldLeft(List.empty[String]){(a,entryname)=>
      val t=entryname.split(";")
      val zip=new java.util.zip.ZipFile(t(0))
      val entry=zip.getEntry(t(1))
      val ret=if(entry!=null){
        val in=zip.getInputStream(entry)
        val r=io.Source.fromInputStream(in).getLines.toList
        in.close
        r
      } else Nil
      zip.close
      a++ret
    }
    t1
  }
}
object StockDB{
  val db=new StockDB("d:/stockdb")
}